package com.xbongbong.pro.service.toolbox.statistic.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartConstant;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.pojo.TimePojo;
import com.xbongbong.pro.statistic.pojo.vo.ContractPerformanceInfoVO;
import com.xbongbong.pro.statistic.result.pojo.ChartPkParamPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPkPojo;
import com.xbongbong.pro.statistic.result.pojo.PkInfoPojo;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO;
import com.xbongbong.pro.statistic.through.pojo.dto.ThroughDTO;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.toolbox.help.SortHelp;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.CompanyConfigModel;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * pk榜相关帮助类
 * @author youli.chen
 * @version v1.0
 * @date 2019/3/12 16:50
 * @since v1.0
 */
@Component
public class PkRuleHelp {
    private static final Logger LOG = LoggerFactory.getLogger(PkRuleHelp.class);
    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private ChartDtoHelp chartDtoHelp;
    @Resource
    private SystemChartHelp systemChartHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private ChartPkRuleHelp chartPkRuleHelp;
    @Resource
    private ThroughHelp throughHelp;
    @Resource
    private ChartRuleQueryHelp chartRuleQueryHelp;

    /**
     * 获取pk榜、部门pk榜统计排序结果
     * 注，此方法只为解决int型pk，如：新增客户数pk、跟进次数pk等
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param indexTypeEnum 索引，用于获取index和type
     * @param boolQueryBuilder 查询条件
     * @param termsAggregationBuilder 聚合条件
     * @param pkType pk类型，具体参见ChartConstant内的PK_USER、PK_DEP
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 14:14
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO getPkResult4Count(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, IndexTypeEnum indexTypeEnum, BoolQueryBuilder boolQueryBuilder, TermsAggregationBuilder termsAggregationBuilder, int pkType) throws XbbException {
        ChartPkParamPojo chartPkParamPojo = chartDtoHelp.getChartPkRuleParamPojo(pkType, userEntity, chartEntity, chartResultPkPojo);
        //页面展示都是以checkUserIdIn为维度展示，所以最终用checkUserIdIn的size + 5作为分桶大小(可能存在userId=0、""、null等的情况)
        int termSize = ChartResultUtil.getTermSize(chartPkParamPojo);
        termsAggregationBuilder.size(termSize);
        // 自定义pk限制分桶数量为100
        if (Objects.equals(chartEntity.getStatisticsType(), StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())) {
            termsAggregationBuilder.size(BasicConstant.CUSTOM_PK_SIZE);
        }
        // es查询结果
        JSONObject resultJsonObject = esHelper.elasticAggs4Buckets2Object(indexTypeEnum, boolQueryBuilder, termsAggregationBuilder);
        JSONArray bucketsArray = resultJsonObject.getJSONArray("buckets");

        if (pkType == ChartConstant.PK_DEP) {
            //部门pk
            return pkCountDep(chartResultPkPojo, chartResultPkDetailVO, chartPkParamPojo, bucketsArray);
        } else {
            //员工pk
            return pkCountUser(userEntity, chartResultPkPojo, chartResultPkDetailVO, chartPkParamPojo, bucketsArray);
        }
    }

    /**
     * 获取pk榜、部门pk榜统计排序结果：double型（所有不需要币种分桶的double型数据分桶sum pk）
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param indexTypeEnum 索引，用于获取index和type
     * @param boolQueryBuilder 查询条件
     * @param fieldGroup 聚合字段（此处是terms）
     * @param sumField 求和的金额字段
     * @param pkType pk类型，具体参见ChartConstant内的PK_USER、PK_DEP
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/4/6 17:18
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO getPkResult4Double(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, IndexTypeEnum indexTypeEnum, BoolQueryBuilder boolQueryBuilder, String fieldGroup, String sumField, int pkType) throws XbbException {
        ChartPkParamPojo chartPkParamPojo = chartDtoHelp.getChartPkRuleParamPojo(pkType, userEntity, chartEntity, chartResultPkPojo);
        //页面展示都是以checkUserIdIn为维度展示，所以最终用checkUserIdIn的size + 5作为分桶大小(可能存在userId=0、""、null等的情况)
        int termSize = ChartResultUtil.getTermSize(chartPkParamPojo);
        /*
          第一层terms：fieldGroup字段分桶，一般为人员
          第二层sum：sumField字段求和
         */
        TermsAggregationBuilder termsAggregationBuilder = esHelper.getTermsAggregation4TwoNoOrder(termSize, fieldGroup, sumField, "aggs01", "aggs02");
        JSONObject resultJsonObject = esHelper.elasticAggs4Buckets2Object(indexTypeEnum, boolQueryBuilder, termsAggregationBuilder);
        JSONArray bucketsArray = resultJsonObject.getJSONArray("buckets");
        //list内部为JSONObject，格式为：uid--该员工的金额
        List<JSONObject> resultList = new ArrayList<>();
        for (Object object : bucketsArray) {
            JSONObject json = (JSONObject) object;
            String userId = json.getString("key");
            //第二层的结果
            Double value = json.getJSONObject("aggs02").getDoubleValue("value");
            //保留2位小数
            value = Arith.div(value, 1, 2);

            JSONObject resultObject = new JSONObject();
            resultObject.put("userId", userId);
            resultObject.put("value", value);
            resultList.add(resultObject);
        }
        return getPkResult4DoubleByResultList(chartPkParamPojo, userEntity, chartResultPkPojo, chartResultPkDetailVO, pkType, resultList);
    }

    /**
     * 获取pk榜、部门pk榜统计排序结果：double型（自定义pk）
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param indexTypeEnum 索引，用于获取index和type
     * @param boolQueryBuilder 查询条件
     * @param pkType pk类型，具体参见ChartConstant内的PK_USER、PK_DEP
     * @param termsAggregationBuilder 聚合条件
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author xinpeng.jiang
     * @date 2021/5/11
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO getPkResult4Double(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, IndexTypeEnum indexTypeEnum, BoolQueryBuilder boolQueryBuilder, TermsAggregationBuilder termsAggregationBuilder, int pkType) throws XbbException {
        ChartPkParamPojo chartPkParamPojo = chartDtoHelp.getChartPkRuleParamPojo(pkType, userEntity, chartEntity, chartResultPkPojo);
        //自定义分桶限制为100
        termsAggregationBuilder.size(BasicConstant.CUSTOM_PK_SIZE);
        JSONObject resultJsonObject = esHelper.elasticAggs4Buckets2Object(indexTypeEnum, boolQueryBuilder, termsAggregationBuilder);
        JSONArray bucketsArray = resultJsonObject.getJSONArray("buckets");
        //list内部为JSONObject，格式为：uid--该员工的金额
        List<JSONObject> resultList = new ArrayList<>();
        HashMap<String, Integer> docCountMap = new HashMap<>(bucketsArray.size());
        for (Object object : bucketsArray) {
            JSONObject json = (JSONObject) object;
            String userId = json.getString("key");
            // 每个桶的总条数
            docCountMap.put(userId, json.getInteger("doc_count"));
            //第二层的结果
            double value = json.getJSONObject("aggs02").getDoubleValue("value");
            //保留2位小数
            value = Arith.div(value, 1, 2);
            JSONObject resultObject = new JSONObject();
            resultObject.put("userId", userId);
            resultObject.put("value", value);
            resultList.add(resultObject);
        }
        chartPkParamPojo.setDocCountMap(docCountMap);
        return getPkResult4DoubleByResultList(chartPkParamPojo, userEntity, chartResultPkPojo, chartResultPkDetailVO, pkType, resultList);
    }

    /**
     * PK数量比例
     *
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 返回结果
     * @param indexTypeEnum 索引，用于获取index和type
     * @param dividendQuery 除数查询条件
     * @param divisorQuery 被除数查询条件
     * @param termsAggregationBuilder 聚合条件
     * @param pkType pk类型
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException elasticAggs4Buckets2Object,getPkResult4DoubleByResultList会产生异常
     * @author 徐俊杰
     * @date 2019/8/23 14:43
     * @since v1.0
     */
    public ChartResultPkDetailVO getPkResult4CountRate(UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo,
                                                       ChartResultPkDetailVO chartResultPkDetailVO, IndexTypeEnum indexTypeEnum,
                                                       BoolQueryBuilder dividendQuery, BoolQueryBuilder divisorQuery,
                                                       TermsAggregationBuilder termsAggregationBuilder, int pkType) throws XbbException {
        ChartPkParamPojo chartPkParamPojo = chartDtoHelp.getChartPkRuleParamPojo(pkType, userEntity, chartEntity, chartResultPkPojo);
        //页面展示都是以checkUserIdIn为维度展示，所以最终用checkUserIdIn的size + 5作为分桶大小(可能存在userId=0、""、null等的情况)
        int termSize = ChartResultUtil.getTermSize(chartPkParamPojo);
        termsAggregationBuilder.size(termSize);
        //除数
        JSONObject dividendResult = esHelper.elasticAggs4Buckets2Object(indexTypeEnum, dividendQuery, termsAggregationBuilder);
        JSONArray dividendBuckets = dividendResult.getJSONArray("buckets");
        //被除数
        JSONObject divisorResult = esHelper.elasticAggs4Buckets2Object(indexTypeEnum, divisorQuery, termsAggregationBuilder);
        JSONArray divisorBuckets = divisorResult.getJSONArray("buckets");
        //除数map
        Map<String, Integer> dividendUserIdCountMap = new HashMap<>(dividendBuckets.size());
        for (int i = 0; i < dividendBuckets.size(); i++) {
            JSONObject dividendJSON = dividendBuckets.getJSONObject(i);
            String userId = dividendJSON.getString("key");
            Integer count = dividendJSON.getInteger("doc_count");
            dividendUserIdCountMap.put(userId, count);
        }
        //结果-比例
        //dividend<=divisor
        List<JSONObject> resultList = new ArrayList<>();
        for (int i = 0; i < divisorBuckets.size(); i++) {
            JSONObject divisorJSON = divisorBuckets.getJSONObject(i);
            String userId = divisorJSON.getString("key");
            Integer dividendCount = dividendUserIdCountMap.get(userId);
            Integer divisorCount = divisorJSON.getInteger("doc_count");
            Double conversion = ChartResultUtil.getRate(dividendCount, divisorCount);
            JSONObject resultJSON = new JSONObject();
            resultJSON.put("userId", userId);
            resultJSON.put("value", conversion);
            resultList.add(resultJSON);
        }
        return getPkResult4DoubleByResultList(chartPkParamPojo, userEntity, chartResultPkPojo, chartResultPkDetailVO, pkType, resultList);
    }

    /**
     * 获取pk榜、部门pk榜统计排序结果：已经通过内存方式汇总出resultList的double型
     * @param chartPkParamPojo 员工/部门pk需要的参数pojo
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param pkType pk类型，具体参见ChartConstant内的PK_USER、PK_DEP
     * @param resultList 员工完成额list，内部格式为uid--该员工完成量的list
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 17:39
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO getPkResult4DoubleByResultList(ChartPkParamPojo chartPkParamPojo, UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, int pkType, List<JSONObject> resultList) throws XbbException {
        if (pkType == ChartConstant.PK_DEP) {
            //部门pk
            return pkDoubleDep(chartResultPkPojo, chartResultPkDetailVO, chartPkParamPojo, resultList);
        }else {
            //员工pk
            return pkDoubleUser(userEntity, chartResultPkPojo, chartResultPkDetailVO, chartPkParamPojo, resultList);
        }
    }

    /**
     * 查询当前登陆人是否在可见权限中
     * @param chartEntity 图表实体
     * @param userEntity 登录实体
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/4/6 16:55
     * @since v1.0
     * @version v1.0
     */
    public boolean checkLoginUserCanSee(ChartEntity chartEntity, UserEntity userEntity) throws XbbException {
        boolean loginUserCanSee = true;
        List<String> scopeUserIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        JSONArray scopeRule = chartEntity.getScopeRule();
        scopeUserIdIn = chartPkRuleHelp.calculationUserList(scopeUserIdIn, userEntity.getCorpid(), scopeRule);
        // 不设置可见范围默认全部可见
        if(CollectionsUtil.isNotEmpty(scopeUserIdIn) && !scopeUserIdIn.contains(userEntity.getUserId())){
            loginUserCanSee = false;
        }
        return loginUserCanSee;
    }

    /**
     * 获取pk榜、部门pk榜统计排序结果：业绩分配金额类pk（合同金额、回款金额、合同毛利），需要处理分配比例等
     * @param performanceInfoVoList 处理后的业绩分配信息list（根据分配比例处理金额、签订/回款时间）
     * @param userEntity 登录员工
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @return com.xbongbong.pro.statistic.result.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/4/6 16:55
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO getPkResult4Performance(List<ContractPerformanceInfoVO> performanceInfoVoList, UserEntity userEntity, ChartEntity chartEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO) throws XbbException {
        List<JSONObject> resultList = systemChartHelp.groupUserAmount4Perfor(performanceInfoVoList);
        int pkType = chartResultPkPojo.getPkType();
        ChartPkParamPojo chartPkParamPojo = chartDtoHelp.getChartPkRuleParamPojo(pkType, userEntity, chartEntity, chartResultPkPojo);
        return getPkResult4DoubleByResultList(chartPkParamPojo, userEntity, chartResultPkPojo, chartResultPkDetailVO, pkType, resultList);
    }

    /**
     * PK榜（员工）--数量排名
     * （一）按照员工业务量排名置入
     * （二）员工所属部门信息（有的不需要，如app端无需显示员工所属部门）
     * @param userEntity 登录员工实体
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param chartPkParamPojo 处理后的用于pk的信息
     * @param bucketsArray es聚合结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/18 14:02
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkCountUser(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, ChartPkParamPojo chartPkParamPojo, JSONArray bucketsArray) throws XbbException {
        //最终筛选，要显示的userIds
        List<String> checkUserIdIn = chartPkParamPojo.getCheckUserIdIn();
        if (checkUserIdIn == null || checkUserIdIn.size() ==0) {
            return chartResultPkDetailVO;
        }
        Map<String, String> nameUserMap = chartPkParamPojo.getNameUserMap();
        Map<String, String> avatarUserMap = chartPkParamPojo.getAvatarUserMap();
        Map<String, Integer> countUserMap = chartPkParamPojo.getCountUserMap();
        Map<Long, String> nameDepMap = chartPkParamPojo.getNameDepMap();
        //userId---所属部门id列表（无部门则value = [1L]）
        Map<String, Set<Long>> userDepSetMap = chartPkParamPojo.getUserDepSetMap();
        SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
        boolean flag = systemCodeEnum != null && (SystemCodeEnum.PK_CUSTOMER_FOLLOW == systemCodeEnum || SystemCodeEnum.PERFORMANCE_CUSTOMER_FOLLOW == systemCodeEnum);
        Integer statisticsType = chartResultPkPojo.getChartEntity().getStatisticsType();
        boolean custom = Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), statisticsType);
        String errorUid = "0";
        String nullUid = "-1";
        Map<String, Integer> docCountMap = new HashMap<>(bucketsArray.size());
        for (Object object : bucketsArray) {
            if (object != null) {
                JSONObject json = (JSONObject) object;
                String uid = json.getString("key");
                Integer count;
                // 把不参与人排除
                boolean errorFlag = !checkUserIdIn.contains(uid) || (!StringUtil.isEmpty(uid) && (uid.equals(errorUid) || uid.equals(nullUid)));
                if (errorFlag) {
                    continue;
                }
                if (flag || custom) {
                    /*
                    1.跟进客户数排名有两层分组：先以userId分组，又以customerId排重cardinality
                    2.自定义pk都走这
                     */
                    count = json.getJSONObject("aggs02").getIntValue("value");
                    // 每个桶的总条数，自定义pk后面对比用
                    docCountMap.put(uid, json.getInteger("doc_count"));
                } else {
                    count = json.getInteger("doc_count");
                }
                countUserMap.put(uid, count);
                if (StringUtil.isEmpty(uid) || uid.equals(errorUid)) {
                    nameUserMap.put(uid, I18nMessageUtil.getMessage(I18nStringConstant.UNKNOW));
                }
            }
        }
        chartPkParamPojo.setDocCountMap(docCountMap);
        //是否显示为0空数据
        boolean pkNullData = companyConfigModel.hasBeenEnable(userEntity.getCorpid(), CompanyConfigEnum.PK_NULL_DATA.getAlias(),"1");
        //员工全公司排名，userId--全公司排名值
        Map<String, Integer> corpRankUserMap = SortHelp.sortMapValueInteger4KeyString(countUserMap, chartResultPkPojo.getTop());
        List<PkInfoPojo> pkData = new ArrayList<>();
        //处理穿透
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPkPojo.getFiscalYearTimePojo(), chartResultPkPojo.getStartTime(), chartResultPkPojo.getEndTime());
        for (Map.Entry<String, Integer> entry : corpRankUserMap.entrySet()) {
            String userId = entry.getKey();
            Integer showValue = countUserMap.get(userId);
            if (!pkNullData && showValue == 0) {
                //不显示为0空数据
                continue;
            }
            chartResultPkPojo.setCount(chartPkParamPojo.getDocCountMap().get(userId));
            PkInfoPojo pkInfoPojo = getPkInfoPojo4User(chartResultPkPojo, userId, entry.getValue(), String.valueOf(showValue), nameUserMap, avatarUserMap, nameDepMap, userDepSetMap, timePojo);
            pkData.add(pkInfoPojo);
        }
        chartResultPkDetailVO.setPkData(pkData);
        return chartResultPkDetailVO;
    }

    /**
     * PK榜（员工）--double类（金额等）排名
     * （一）按照员工业务量排名置入
     * （二）员工所属部门信息（有的不需要，如app端无需显示员工所属部门）
     * @param userEntity 登录员工实体
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param chartPkParamPojo 处理后的用于pk的信息
     * @param resultList 员工完成额list，内部格式为uid--该员工完成量的list
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @throws XbbException
     * @author zcp
     * @date 2019/3/20 14:03
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkDoubleUser(UserEntity userEntity, ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, ChartPkParamPojo chartPkParamPojo, List<JSONObject> resultList) throws XbbException {
        ChartEntity chartEntity = chartResultPkPojo.getChartEntity();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(chartEntity.getNumFormat());
        //最终筛选，要显示的userIds
        List<String> checkUserIdIn = chartPkParamPojo.getCheckUserIdIn();
        if (checkUserIdIn == null || checkUserIdIn.size() ==0) {
            return chartResultPkDetailVO;
        }
        Map<String, String> nameUserMap = chartPkParamPojo.getNameUserMap();
        Map<String, String> avatarUserMap = chartPkParamPojo.getAvatarUserMap();
        Map<String, Double> amountUserMap = chartPkParamPojo.getAmountUserMap();
        Map<Long, String> nameDepMap = chartPkParamPojo.getNameDepMap();
        //userId---所属部门id列表（无部门则value = [1L]）
        Map<String, Set<Long>> userDepSetMap = chartPkParamPojo.getUserDepSetMap();
        String errorUid = "0";
        String nullUid = "-1";
        for (JSONObject json : resultList) {
            String userId = json.getString("userId");
            Double value = json.getDouble("value");
            amountUserMap.put(userId, value);
            if (StringUtil.isEmpty(userId) || userId.equals(errorUid)) {
                nameUserMap.put(userId, I18nMessageUtil.getMessage(I18nStringConstant.UNKNOW));
            }
        }
        //是否显示为0空数据
        boolean pkNullData = companyConfigModel.hasBeenEnable(userEntity.getCorpid(), CompanyConfigEnum.PK_NULL_DATA.getAlias(),"1");
        //员工全公司排名，userId--全公司排名值
        Map<String, Integer> corpRankUserMap = SortHelp.sortMapValueDouble4KeyString(amountUserMap, chartResultPkPojo.getTop());
        List<PkInfoPojo> pkData = new ArrayList<>();
        //处理穿透
        TimePojo timePojo = throughHelp.formatThroughTimeInfo(false, chartResultPkPojo.getFiscalYearTimePojo(), chartResultPkPojo.getStartTime(), chartResultPkPojo.getEndTime());
        for (Map.Entry<String, Integer> entry : corpRankUserMap.entrySet()) {
            String userId = entry.getKey();
            boolean errorFlag = !checkUserIdIn.contains(userId) || (!StringUtil.isEmpty(userId) && (userId.equals(errorUid) || userId.equals(nullUid)));
            if (errorFlag) {
                continue;
            }
            Double showValue = amountUserMap.get(userId);
            if (!pkNullData && showValue == 0) {
                //不显示为0空数据
                continue;
            }
            if (Objects.nonNull(chartPkParamPojo.getDocCountMap())) {
                chartResultPkPojo.setCount(chartPkParamPojo.getDocCountMap().get(userId));
            }
            String value;
            if (chartResultPkPojo.getPerformancePk()) {
                //目标完成情况的使用NumFormatEnum.DEFAULT，最终单位格式在外部统一格式化（计算完成率等）  -- 部门的不用处理，是因为部门的不使用人员聚合，而是部门id获取到userIdList作为条件查询
                value = ChartResultUtil.formatValue2Double(false, chartResultPkPojo.getValueTypeEnum(), false, showValue, NumFormatEnum.DEFAULT, false);
            } else {
                value = ChartResultUtil.formatValue2Double(false, chartResultPkPojo.getValueTypeEnum(), false, showValue, numFormatEnum, false);
            }
            PkInfoPojo pkInfoPojo = getPkInfoPojo4User(chartResultPkPojo, userId, entry.getValue(), value, nameUserMap, avatarUserMap, nameDepMap, userDepSetMap, timePojo);
            pkData.add(pkInfoPojo);
        }
        chartResultPkDetailVO.setPkData(pkData);
        return chartResultPkDetailVO;
    }

    /**
     * PK榜（部门）--数量排名
     * （一）按照部门业务量排名置入
     * （二）员工所属部门信息（有的不需要，如app端无需显示员工所属部门）
     * @param chartResultPkPojo pk参数pojo
     * @param chartResultPkDetailVO 塞入pk返回结果
     * @param chartPkParamPojo 处理后的用于pk的信息
     * @param bucketsArray es聚合结果
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @author zcp
     * @date 2019/3/15 22:32
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkCountDep(ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, ChartPkParamPojo chartPkParamPojo, JSONArray bucketsArray){
        //部门id---部门名称	（无部门则key = 1L）
        Map<Long, String> nameDepMap = chartPkParamPojo.getNameDepMap();
        //部门id---部门总业务数量
        Map<Long, Integer> countDepMap = chartPkParamPojo.getCountDepMap();
        //userId---所属部门id列表（无部门则value = [1L]）
        Map<String, Set<Long>> userDepSetMap = chartPkParamPojo.getUserDepSetMap();
        List<String> checkUserIdIn = chartPkParamPojo.getCheckUserIdIn();
        //包含下属部门的
        Set<Long> includeSubDepIds = chartResultPkPojo.getIncludeSubDepIds();

        SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
        boolean flag = systemCodeEnum != null && (SystemCodeEnum.PK_CUSTOMER_FOLLOW == systemCodeEnum || SystemCodeEnum.PERFORMANCE_CUSTOMER_FOLLOW == systemCodeEnum);
        Integer statisticsType = chartResultPkPojo.getChartEntity().getStatisticsType();
        boolean custom = Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), statisticsType);
        //部门id---部门跟进客户ids
        Map<Long, Set<Long>> countDepCidMap = new HashMap(bucketsArray.size());
        for (Object object : bucketsArray) {
            if (object != null) {
                JSONObject json = (JSONObject) object;
                String uid = json.getString("key");
                if (!checkUserIdIn.contains(uid)) {
                    continue;
                }
                Integer count;
                if (flag) {
                    //跟进客户数排名有两层分组：先以userId分组，又以customerId分组terms
                    JSONArray twoBuckets = json.getJSONObject("aggs02").getJSONArray("buckets");
                    //该员工跟进的所有客户ids
                    Set<Long> userCustomerIds = new HashSet<>();
                    for (Object two : twoBuckets) {
                        if (two != null) {
                            JSONObject twoJson = (JSONObject) two;
                            Long customerId = twoJson.getLong("key");
                            userCustomerIds.add(customerId);
                        }
                    }
                    Set<Long> depSet = userDepSetMap.get(uid);
                    for (Long belongDepId : depSet) {
                        //所属部门跟进客户数量
                        Set<Long> depCustomerIdSet = countDepCidMap.get(belongDepId);
                        if (depCustomerIdSet == null) {
                            depCustomerIdSet = userCustomerIds;
                        }else {
                            depCustomerIdSet.addAll(userCustomerIds);
                        }
                        countDepCidMap.put(belongDepId, depCustomerIdSet);
                        countDepMap.put(belongDepId, depCustomerIdSet.size());
                    }
                } else if (custom) {
                    // 自定义pk
                    count = json.getJSONObject("aggs02").getIntValue("value");
                    Set<Long> depSet = userDepSetMap.get(uid);
                    for (Long belongDepId : depSet) {
                        Integer perCount = countDepMap.get(belongDepId);
                        perCount += count;
                        countDepMap.put(belongDepId, perCount);
                    }
                } else {
                    count = json.getInteger("doc_count");
                    //userDepSetMap.get(uid) == null即无部门情况，上面方法内部已处理
                    Set<Long> depSet = userDepSetMap.get(uid);
                    for (Long belongDepId : depSet) {
                        Integer perCount = countDepMap.get(belongDepId);
                        perCount += count;
                        countDepMap.put(belongDepId, perCount);
                    }
                }
            }
        }
        //部门全公司排名，depId--全公司排名值
        Map<Long, Integer> corpRankDepMap = SortHelp.sortMapValueInteger4KeyLong(countDepMap, chartResultPkPojo.getTop());

        List<PkInfoPojo> pkData = new ArrayList<>();
        //（一）按照部门业务量排序，tableArray置入depId,depName,showValue,corpRank
        for (Map.Entry<Long, Integer> entry : corpRankDepMap.entrySet()) {
            Long belongDepId = entry.getKey();
            Integer rank = entry.getValue();
            Integer showValue = countDepMap.get(belongDepId);
            PkInfoPojo pkInfoPojo = getPkInfoPojo4Dep(includeSubDepIds, belongDepId, nameDepMap.get(belongDepId), rank, String.valueOf(showValue));
            pkData.add(pkInfoPojo);
        }
        chartResultPkDetailVO.setPkData(pkData);
        return chartResultPkDetailVO;
    }

    /**
     * PK榜（部门）--金额排名
     * （一）按照部门业务量排名置入
     * （二）员工所属部门信息（有的不需要，如app端无需显示员工所属部门）
     * @param chartResultPkPojo
     * @param chartResultPkDetailVO
     * @param chartPkParamPojo
     * @param resultList 员工完成额list，内部格式为uid--该员工完成量的list
     * @return com.xbongbong.pro.statistic.pojo.vo.ChartResultPkDetailVO
     * @author zcp
     * @date 2019/3/20 15:11
     * @since v1.0
     * @version v1.0
     */
    public ChartResultPkDetailVO pkDoubleDep(ChartResultPkPojo chartResultPkPojo, ChartResultPkDetailVO chartResultPkDetailVO, ChartPkParamPojo chartPkParamPojo, List<JSONObject> resultList){
        ChartEntity chartEntity = chartResultPkPojo.getChartEntity();
        NumFormatEnum numFormatEnum = NumFormatEnum.getByCode(chartEntity.getNumFormat());
        //部门id---部门名称	（无部门则key = 1L）
        Map<Long, String> nameDepMap = chartPkParamPojo.getNameDepMap();
        //部门id---部门总业务数量
        Map<Long, Double> amountDepMap = chartPkParamPojo.getAmountDepMap();
        //userId---所属部门id列表（无部门则value = [1L]）
        Map<String, Set<Long>> userDepSetMap = chartPkParamPojo.getUserDepSetMap();
        List<String> checkUserIdIn = chartPkParamPojo.getCheckUserIdIn();
        //包含下属部门的
        Set<Long> includeSubDepIds = chartResultPkPojo.getIncludeSubDepIds();

        for (JSONObject json : resultList) {
            String userId = json.getString("userId");
            Double value = json.getDouble("value");
            if (!checkUserIdIn.contains(userId)) {
                continue;
            }
            //userDepSetMap.get(uid) == null即无部门情况，上面方法内部已处理
            Set<Long> depSet = userDepSetMap.get(userId);
            for (Long belongDepId : depSet) {
                Double perValue = amountDepMap.get(belongDepId);
                perValue += value;
                amountDepMap.put(belongDepId, perValue);
            }
        }
        //部门全公司排名，depId--全公司排名值
        Map<Long, Integer> corpRankDepMap = SortHelp.sortMapValueDouble4KeyLong(amountDepMap, chartResultPkPojo.getTop());

        List<PkInfoPojo> pkData = new ArrayList<>();
        //（一）按照部门业务量排序，tableArray置入depId,depName,showValue,corpRank
        for (Map.Entry<Long, Integer> entry : corpRankDepMap.entrySet()) {
            Long belongDepId = entry.getKey();
            Integer rank = entry.getValue();
            Double showValue = amountDepMap.get(belongDepId);
            String value = ChartResultUtil.formatValue2Double(false, chartResultPkPojo.getValueTypeEnum(), false, showValue, numFormatEnum, false);
            PkInfoPojo pkInfoPojo = getPkInfoPojo4Dep(includeSubDepIds, belongDepId, nameDepMap.get(belongDepId), rank, value);
            pkData.add(pkInfoPojo);
        }
        chartResultPkDetailVO.setPkData(pkData);
        return chartResultPkDetailVO;
    }


    //==================== private method ====================

    /**
     * 封装员工pk信息
     * @param chartResultPkPojo pk参数pojo
     * @param userId 员工id
     * @param rank 排名
     * @param showValue 值
     * @param nameUserMap userId--员工姓名
     * @param avatarUserMap userId--员工头像
     * @param nameDepMap 部门id---部门名称（无部门则key = 1L）
     * @param userDepSetMap userId---所属部门id列表（无部门则value = [1L]）
     * @param timePojo 穿透时间参数pojo
     * @return com.xbongbong.pro.statistic.pojo.PkInfoPojo
     * @author zcp
     * @date 2019/3/26 19:59
     * @since v1.0
     * @version v1.0
     */
    public PkInfoPojo getPkInfoPojo4User(ChartResultPkPojo chartResultPkPojo, String userId, Integer rank, String showValue, Map<String, String> nameUserMap, Map<String, String> avatarUserMap, Map<Long, String> nameDepMap, Map<String, Set<Long>> userDepSetMap, TimePojo timePojo) {
        PkInfoPojo pkInfoPojo = new PkInfoPojo();
        ChartEntity chartEntity = chartResultPkPojo.getChartEntity();
        pkInfoPojo.setId(userId);
        pkInfoPojo.setName(nameUserMap.get(userId));
        if (avatarUserMap != null) {
            pkInfoPojo.setAvatar(avatarUserMap.get(userId));
        }
        pkInfoPojo.setValue(showValue);
        pkInfoPojo.setRank(rank);
        // 处理穿透，自定义和系统分开
        String through;
        if (Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(), chartEntity.getStatisticsType())) {
            // 把现在的user作为选中user传给前端
            chartResultPkPojo.setCheckedUserId(userId);
            through = chartRuleQueryHelp.getThrough(chartEntity, chartResultPkPojo);
        } else {
            //移动端产品销量不穿透
            ThroughDTO throughDTO = null;
            SystemCodeEnum systemCodeEnum = chartResultPkPojo.getSystemCodeEnum();
            if (throughHelp.checkThrough(chartResultPkPojo, systemCodeEnum)) {
                //强制单选
                chartResultPkPojo.setSingleCheck(true);
                throughDTO = new ThroughDTO(chartResultPkPojo, null, userId, systemCodeEnum);
            }
            through = throughHelp.getThrough(throughDTO, timePojo);
        }
        pkInfoPojo.setThrough(through);
        //--------------不显示部门，则无需处理部门的情况
        //是否处理部门信息
        Boolean pkShowDep = chartResultPkPojo.getPkShowDep();
        if (!pkShowDep) {
            return pkInfoPojo;
        }
        StringBuilder depName = new StringBuilder();
        //userDepMap.get(uid) == null即无部门情况，上面已处理
        Set<Long> depIdSet = userDepSetMap.get(userId);
        //员工所属部门名称（可能多个部门）
        for (Long did : depIdSet) {
            if (depName.length() != 0) {
                depName.append(",");
            }
            depName.append(nameDepMap.get(did));
        }
        pkInfoPojo.setDepName(depName.toString());
        return pkInfoPojo;
    }
    /**
     * 封装部门pk信息
     * @param includeSubDepIds 部门绩效pk方案---包含下属部门的
     * @param belongDepId 部门id
     * @param name 部门名称
     * @param rank 排名
     * @param showValue 值
     * @return com.xbongbong.pro.statistic.pojo.PkInfoPojo
     * @author zcp
     * @date 2019/3/26 19:38
     * @since v1.0
     * @version v1.0
     */
    public PkInfoPojo getPkInfoPojo4Dep(Set<Long> includeSubDepIds, Long belongDepId, String name, Integer rank, String showValue) {
        //是否包含子部门，true否false是
        Boolean includeSub = includeSubDepIds != null && includeSubDepIds.contains(belongDepId);
        //不显示为0空数据

        PkInfoPojo pkInfoPojo = new PkInfoPojo();
        pkInfoPojo.setId(String.valueOf(belongDepId));
        pkInfoPojo.setDepName(name);
        pkInfoPojo.setValue(showValue);
        pkInfoPojo.setRank(rank);
        pkInfoPojo.setIncludeSub(includeSub);
        return pkInfoPojo;
    }
}
